﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ICeFramework.Common.DataLayer.Enums;
using System.Runtime.Serialization;

namespace ICeFramework.Common.DataLayer
{
    [Serializable, DataContract]
    //[KnownType(typeof(System.r
    public class EntityFilter
    {
        public static EntityFilter NullValue = null;

        private EntityFilter _filter1;
        [DataMember]
        public EntityFilter Filter1
        {
            get { return _filter1; }
            set { _filter1 = value; }
        }
        private EntityFilter _filter2;
        [DataMember]
        public EntityFilter Filter2
        {
            get { return _filter2; }
            set { _filter2 = value; }
        }

        private EntityColumn _column;
        [DataMember]
        public EntityColumn Column
        {
            get { return _column; }
            set { _column = value; }
        }

        private object _expression;
        [DataMember]
        public object Expression
        {
            get { return _expression; }
            set { _expression = value; }
        }

        private string _operator;
        [DataMember]
        public string Operator
        {
            get { return _operator; }
            set { _operator = value; }
        }
        
        private string _paramName;
        [DataMember]
        private DataParameterCollection _parameters = new DataParameterCollection();

        #region public static EntityFilter operator |(EntityFilter a, EntityFilter b)
        /// <summary>
        /// 
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static EntityFilter operator |(EntityFilter a, EntityFilter b)
        {
            if ((object)a != null && (object)b != null)
            {
                EntityFilter q = new EntityFilter();
                q.Filter1 = a;
                q.Filter2 = b;
                q.Operator = "OR";
                return q;
            }

            if ((object)a == null && (object)b != null)
                return b;
            if ((object)a != null && (object)b == null)
                return a;

            return null;
        }
        #endregion

        #region public static EntityFilter operator &(EntityFilter a, EntityFilter b)
        /// <summary>
        /// 
        /// </summary>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <returns></returns>
        public static EntityFilter operator &(EntityFilter a, EntityFilter b)
        {
            if ((object)a != null && (object)b != null)
            {
                EntityFilter q = new EntityFilter();
                q.Filter1 = a;
                q.Filter2 = b;
                q.Operator = "AND";
                return q;
            }

            if ((object)a == null && (object)b != null)
                return b;
            if ((object)a != null && (object)b == null)
                return a;
            return null;
        }
        #endregion

        public DataParameterCollection FilterParameters()
        {
            _parameters.Clear();
            if ((object)_filter1 == null)
            {
                if (!(_expression is EntityColumn))
                {
                    _parameters.Add(new DataParameter(_paramName, _expression, _column.DbType));
                }
            }
            else
            {
                AddParameters(_filter1.FilterParameters());
                AddParameters(_filter2.FilterParameters());
            }
            return _parameters;
        }

        protected void AddParameters(DataParameterCollection parameters)
        {
            foreach (DataParameter parm in parameters)
            {
                _parameters.Add(parm);
            }
        }


        public void SetParameterName(string paramPrefix)
        {
            paramPrefix = new StringBuilder().AppendFormat("{0}p_", paramPrefix).ToString();
            if (!(_expression is EntityColumn))
            {
                _paramName = String.Format("{0}0", paramPrefix);
            }
            if ((object)_filter1 != null)
            {
                _filter1.SetParameterName(new StringBuilder().AppendFormat("{0}1", paramPrefix).ToString());
                _filter2.SetParameterName(new StringBuilder().AppendFormat("{0}2", paramPrefix).ToString());
            }
        }

        public string ToSQLCommand()
        {
            StringBuilder sb = new StringBuilder();
            if ((object)_filter1 == null)
            {
                if (_expression is EntityColumn)
                {
                    return sb.AppendFormat("({0}{1}{2})", _column.Name, _operator, (_expression as EntityColumn).Name).ToString();
                }
                else
                {
                    if (_expression == null)
                    {
                        return sb.AppendFormat("({0}{1}NULL)", _column.Name, _operator).ToString();
                    }
                    else
                    {
                        if (_expression.GetType() == typeof(Int16) ||
                            _expression.GetType() == typeof(Int32) ||
                            _expression.GetType() == typeof(Int64) ||
                            _expression.GetType() == typeof(Decimal))
                        {
                            return sb.AppendFormat("({0}{1}{2})", _column.Name, _operator, _expression.ToString()).ToString();
                        }
                        else if (_column.GetType() == typeof(string))
                        {
                            return sb.AppendFormat("({0}{1}'{2}')", _column.Name, _operator, _expression).ToString();
                        }
                        else if (_column.GetType() == typeof(DateTime))
                        {
                            return sb.AppendFormat("({0}{1}'{2}')", _column.Name, _operator, ((DateTime)_expression).ToString()).ToString();
                        }
                        else if (_column.GetType() == typeof(bool))
                        {
                            return sb.AppendFormat("({0}{1}{2})", _column.Name, _operator, (((bool)_expression) ? '1' : '0').ToString()).ToString();
                        }
                        else
                        {
                            throw new ApplicationException("Method EntityFilter.ToSQLCommand() is not implemented for parameter type " + _expression.GetType().ToString());
                        }
                    }
                }
            }
            else
            {
                return sb.AppendFormat("({0}{1}{2})", _filter1.ToSQLCommand(), _operator, _filter1.ToSQLCommand()).ToString();
            }
        }



    }
}
